package com.shinemo.mpush.alloc.utils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.shinemo.mpush.alloc.exception.CommunicationErrorException;

/**
 * 调用apache HttpClients
 *
 * @author gary.zhi
 * @date Aug 21, 2018 9:04:00 PM
 */
public class HttpUtils {

    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);

    private static int connectTimeout = 1000;
    private static int socketTimeout = 2000;

    private HttpUtils() {
    }

    public static <T> T post(String url, List<NameValuePair> params, Class<T> clazz)
            throws CommunicationErrorException {
        return parseObject(post(url, params), clazz);
    }

    public static <T> T post(String url, List<NameValuePair> params, Map<String, String> headers, Class<T> clazz)
            throws CommunicationErrorException {
        return parseObject(post(url, params, headers), clazz);
    }

    public static <T> T get(String url, Map<String, String> headers, Class<T> clazz)
            throws CommunicationErrorException {
        return parseObject(get(url, headers), clazz);
    }

    public static <T> T get(String url, Class<T> clazz) throws CommunicationErrorException {
        return parseObject(get(url), clazz);
    }

    public static <T> T parseObject(String response, Class<T> clazz) {
        return StringUtils.isEmpty(response) ? null : JSON.parseObject(response, clazz);
    }

    public static String get(String url) throws CommunicationErrorException {
        return get(url, Collections.emptyMap());
    }

    public static String get(String url, Map<String, String> headers)
            throws CommunicationErrorException {

        return execute(HttpGet.METHOD_NAME, url, null, headers);
    }

    public static String post(String url, List<NameValuePair> params) throws CommunicationErrorException {
        return post(url, params, Collections.emptyMap());
    }

    public static String post(String url, List<NameValuePair> params, Map<String, String> headers)
            throws CommunicationErrorException {
        return execute(HttpPost.METHOD_NAME, url, params, headers);
    }

    public static String execute(String method, String url, List<NameValuePair> params)
            throws CommunicationErrorException {
        return execute(method, url, params, Collections.emptyMap());
    }

    public static String execute(String method, String url, List<NameValuePair> params, Map<String, String> headers)
            throws CommunicationErrorException {

        try (CloseableHttpClient closeableHttpClient = HttpClients.createDefault()) {

            String contentType = ContentType.APPLICATION_FORM_URLENCODED.toString();
            BasicHeader basicHeader = new BasicHeader("Content-Type", contentType);
            RequestBuilder builder = RequestBuilder.create(method).addHeader(basicHeader).setUri(url);

            if (null == headers) {
                headers = Collections.emptyMap();
            }
            headers.entrySet().forEach(entry -> builder.addHeader(new BasicHeader(entry.getKey(), entry.getValue())));


            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout)
                    .setSocketTimeout(socketTimeout).build();

            builder.setConfig(requestConfig);

            if (null != params) {
                builder.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8.name()));
            }

            return getSuccessfulResponse(closeableHttpClient.execute(builder.build()));

        } catch (IOException e) {
            log.error("visiting '{}' occur  error", url);
            throw new CommunicationErrorException(e);
        }
    }

    /**
     * 获取status code=200的响应数据,其他状态将返回空字符串并记录失败日志
     *
     * @param httpResponse
     * @return
     * @throws ParseException
     * @throws IOException
     */
    public static String getSuccessfulResponse(HttpResponse httpResponse) throws IOException {
        if (!isRequestSuccessful(httpResponse)) {
            int statusCode = httpResponse.getStatusLine().getStatusCode();
            log.error("Status Code:{},Response:{}", statusCode, httpResponse);
            return "";
        }
        return getHttpResponse(httpResponse);
    }

    public static String getHttpResponse(HttpResponse httpResponse) throws IOException {
        return getHttpResponse(httpResponse, StandardCharsets.UTF_8.name());
    }

    public static String getHttpResponse(HttpResponse httpResponse, String defaultCharset) throws IOException {

        String response = EntityUtils.toString(httpResponse.getEntity(), defaultCharset);
        if (log.isInfoEnabled()) {
            log.info("Response:{}", response);
        }

        return response;
    }

    public static boolean isRequestSuccessful(HttpResponse httpResponse) {
        return httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
    }
}
